// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ValueMetadataCollection.cs" company="AzureContrib (Open source library http://azurecontrib.codeplex.com)">
//   Microsoft Public License (Ms-PL)
// </copyright>
// <summary>
//   Base class for an <see cref="IValueMetadataCollection{TValue,TMetadata,TValueMetadata}" />.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;

using AzureContrib.WindowsAzure.ServiceRuntime.ServiceLocation;

namespace AzureContrib.WindowsAzure.MEF
{
	/// <summary>
	/// Base class for an <see cref="IValueMetadataCollection{TValue,TMetadata,TValueMetadata}"/>.
	/// </summary>
	/// <typeparam name="TValue">The type of value to compact</typeparam>
	/// <typeparam name="TMetadata">The type of metadata to compact</typeparam>
	/// <typeparam name="TValueMetadata">The resuting combination value-metadata</typeparam>
	public abstract class ValueMetadataCollection<TValue, TMetadata, TValueMetadata> : IValueMetadataCollection<TValue, TMetadata, TValueMetadata> where TValueMetadata : TValue, TMetadata
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="ValueMetadataCollection{TValue,TMetadata,TValueMetadata}"/> class. 
		/// </summary>
		protected ValueMetadataCollection()
		{
			ValueMetadatas = Enumerable.Empty<Lazy<TValueMetadata>>();
			ValuesWithMetadata = Enumerable.Empty<Lazy<TValue, TMetadata>>();
		}

		/// <summary>
		/// Gets or sets the current <typeparamref name="TValueMetadata"/> tasks that might be implemented direct in the application.
		/// </summary>
		[ImportMany(AllowRecomposition = true)]
		public IEnumerable<Lazy<TValueMetadata>> ValueMetadatas { get; set; }

		/// <summary>
		/// Gets or sets the current <typeparamref name="TValue" /> implementations in the application that carry <typeparamref name="TMetadata"/>
		/// </summary>
		[ImportMany(AllowRecomposition = true)]
		public IEnumerable<Lazy<TValue, TMetadata>> ValuesWithMetadata { get; set; }

		/// <summary>
		/// Gets the <see cref="Lazy{T}"/> <see cref="IBuilder"/> to use.
		/// </summary>
		protected Lazy<IBuilder> Builder { get; private set; }

		/// <summary>
		/// Creates a <typeparamref name="TValueMetadata"/> instance from the <see cref="Lazy{T}"/> with T = <typeparamref name="TValue"/> and <typeparamref name="TMetadata"/>.
		/// </summary>
		/// <param name="lazyValueMetadata">The lazy Value Metadata to compact into one instance.</param>
		/// <returns>
		/// The resulting <typeparamref name="TValueMetadata"/> instance.
		/// </returns>
		public abstract TValueMetadata Compact(Lazy<TValue, TMetadata> lazyValueMetadata);

		/// <summary>
		/// All of the instances compacted and nice as one <see cref="IEnumerable{T}.GetEnumerator"/>.
		/// </summary>
		/// <returns>
		/// The enumerator of all the instances.
		/// </returns>
		public IEnumerator<TValueMetadata> GetEnumerator()
		{
			foreach (var lazyWorkItem in ValuesWithMetadata)
			{
				yield return Compact(lazyWorkItem);
			}

			foreach (var valueMetadata in ValueMetadatas)
			{
				yield return valueMetadata.Value;
			}
		}

		/// <summary>
		/// A standard <see cref="IEnumerable.GetEnumerator"/>.
		/// </summary>
		/// <returns>
		/// The enumerator.
		/// </returns>
		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		/// <summary>
		/// The actual <see cref="Lazy{T}"/> <see cref="IBuilder"/> which will be set at some point in time and lazily used later.
		/// </summary>
		/// <param name="lazyBuilder">The <see cref="Lazy{T}"/> <see cref="IBuilder"/> to use.</param>
		public void SetBuilder(Lazy<IBuilder> lazyBuilder)
		{
			Builder = lazyBuilder;
		}
	}
}